iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Modern Web

一些讓你看來很強的 ORM - prisma系列 第 19

Day19. 一些讓你看來很強的 ORM - prisma (customer methods)

  • 分享至 

  • xImage
  •  

prisma client 中除了昨天介紹的透過 zodprisma.$extendsvalidate query input,以及透過 prisma.$extends.resultComputed fields 外,其實還有其他的功能,在 prisma.$extends 我們也可以客製化 modelmethods 至於怎麼做到我們繼續看下去

Demo

一樣這是今天的 model

  • Useremailpassword 欄位
  • 獨立一個 Password model 去管理 user
model User {
  id       String    @id @default(cuid())
  email    String
  password Password?
}

model Password {
  hash   String
  user   User   @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId String @unique
}

我們今天的範例主要是做一個 user 註冊的功能,所以我們 User model 才會有 email 以及 password 的欄位,通常我們在 create User 的時候,我們不會在 DB 直接存取 password ,取而代之的是我們會存 hash 過後的內容,以防止 userpassword 被偷走,在 $extends 中我們實作 signUp 邏輯

這邊我們需要先 install bcryptjs 來幫我們 hash password

>npm i bcryptjs
>npm i --save-dev @types/bcryptjs

$extends.model 中我們可以自訂想要的 function 在特定的 model 裡,在 user.signUp 我們吃兩個參數 emailpassword ,為了防止 userpassword 存到 DB ,所以我們使用 bcrypt 幫我們 hash password,最後我們 return create user 的結果

import bcrypt from 'bcryptjs'
const prismaClient = new PrismaClient().$extends({
  model: {
    user: {
      signUp: async (email: string, password: string) => {
        const hash = await bcrypt.hash(password, 10)
        return prismaClient.user.create({
          data: {
            email,
            password: {
              create: {
                hash
              }
            }
          }
        })
      }
    }
  }
})

使用 signUp 這個 function 也很簡單,所有在 $extends.model 的內容,prisma client 都會自動幫你產生對應的 type,使用起來非常方便

https://ithelp.ithome.com.tw/upload/images/20241003/20145677UfJgVXfE4z.png

如此我們就成功 create 一個 user 了~

const user = await prismaClient.user.signUp('hiunji64@gmail.com', '123456')
{
  user: { id: 'cm1te0z5r0000p581g6thkkqn', email: 'hiunji64@gmail.com' }
}

接著我們在定另外一個 function ,去找到使用特定 domain 當作 emailuser 有哪些,如以下的 findManyByDomain

const prismaClient = new PrismaClient().$extends({
  model: {
    user: {
      //..
      findManyByDomain: (domain: string) => {
        return prismaClient.user.findMany({
          where: {
            email: {
              endsWith: `@${domain}`
            }
          }
        })
      }
    }
  }
})

如此我們就可以透過 findManyByDomain 拿查詢內容拉,是不是簡化非常多~

const userLists = await prismaClient.user.findManyByDomain('gmail.com')
{
  userLists: [
    { id: 'cm1tcqxoz0000b1cl7j9dy9xb', email: 'hiunji64@gmail.com' }
  ]
}

最後我們再補充一個 signIn 來驗證 useremail 或是 password 是否正確,步驟如下:

  • 如果 findUser 有資料,代表 email 是正確的,沒有的話直接 return user not found
  • bcrypt.compare 去驗證 findUser.password.hash 是否跟 inputpassword 是否一樣
const prismaClient = new PrismaClient().$extends({
  model: {
    user: {
      //..
      signIn: async (email: string, password: string) => {
        const findUser = await prismaClient.user.findFirst({
          where: {
            email
          },
          include: {
            password: true
          }
        })
        if (findUser === null) {
          return 'user not found'
        }

        const verifyResult = await bcrypt.compare(password, findUser.password?.hash ?? '')
        return {
          verifyResult
        }
      }
    }
  }
})

接著我們測試一下如果 input 不存在的 email,顯然有正確 return user not found

 const result = await prismaClient.user.signIn('aaa@gmail.com', '123456')
{ result: 'user not found' }

如果 email 正確蛋 password 錯誤,則 verifyResult 就是 false

const result = await prismaClient.user.signIn('hiunji64@gmail.com', '123456dd')
{ result: { verifyResult: false } }

反之如果 password 正確則驗證就成功了,之後就可以呼叫 prismaClient.user.signIn 去判斷 input 的來源是否正確~

 const result = await prismaClient.user.signIn('hiunji64@gmail.com', '123456')
{ result: { verifyResult: true } }

以上就是今天的內容希望大家喜歡~

大家如果有問題可以來小弟的群組討論~

✅ 前端社群 :
https://lihi3.cc/kBe0Y


上一篇
Day18. 一些讓你看來很強的 ORM - prisma (zod validate)
下一篇
Day20. 一些讓你看來很強的 ORM - prisma (Omit Fields )
系列文
一些讓你看來很強的 ORM - prisma30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言